#ifndef STATELANDING_H
#define STATELANDING_H

#include "state.h"
#include "stateid.h"
#include "../manager.h"
#include "../eventmanager.h"
#include "../parammanager.h"
#include "../properties.h"

namespace state {

const int LANDINGCUTPOWER_TIME = 50000;
	

struct BaroGlide : public State {
	BaroGlide(int id) : State(id) {}

	virtual void onEnter() {
		ParamManager *parammgr = Manager::Instance().getParamManager();

		PropAccessor p;

		p().fcs.roll.set(Roll_TrackApp, 30);
#if defined(FILIN2)
		p().fcs.pitch.set(Pitch_GlidePath_Baro);
#else
		p().fcs.pitch.set(Pitch_GlidePath_Baro, parammgr->getFloat(ParamManager::BAROALT_MINIMUM));
#endif
		p().fcs.yaw.set(Yaw_Damper);
		p().fcs.throttle.set(Throttle_Airspeed, parammgr->getFloat(ParamManager::VAPPROACH) / 3.6f);
		p().fcs.flaps.set(Flaps_Value, Flaps_Value_Landing);
		p().fcs.brakes.set(Brakes_Value, 0);
		
		p().fcs.watcher = Watcher_Idle;	// ***

		p().fcs.state = getId();
	}
};


#if defined(FILIN2)

struct VyGlide : public State {
	VyGlide(int id) : State(id) {}
	
	virtual void onEnter() {
		PropAccessor p;
		p().fcs.roll.set(Roll_TrackApp, 15);
		p().fcs.pitch.set(Pitch_VSpeed, -1.0f);
		p().fcs.yaw.set(Yaw_Damper);		
		p().fcs.throttle.set(Throttle_Airspeed, Manager::Instance().getParamManager()->getFloat(ParamManager::VAPPROACH) / 3.6f);
		p().fcs.flaps.set(Flaps_Value, Flaps_Value_Landing);
		p().fcs.brakes.set(Brakes_Value, 0);

		p().fcs.watcher = Watcher_Idle;

		p().fcs.state = getId();
	}
};

#else

struct DirectGlide : public State {
	DirectGlide(int id) : State(id) {}

	virtual void onEnter(){
		ParamManager *parammgr = Manager::Instance().getParamManager();

		PropAccessor p;

		const float directAltFlare = 2; // parammgr->getFloat(ParamManager::DIRECTALT_FLARE)

		p().fcs.roll.set(Roll_TrackApp, 15);
		p().fcs.pitch.set(Pitch_GlidePath_Direct, directAltFlare);
		p().fcs.yaw.set(Yaw_Damper);
		p().fcs.throttle.set(Throttle_Airspeed, parammgr->getFloat(ParamManager::VAPPROACH) / 3.6f);
		p().fcs.flaps.set(Flaps_Value, Flaps_Value_Landing);
		p().fcs.brakes.set(Brakes_Value, 0);

		p().fcs.watcher = Watcher_Idle;

		p().fcs.state = getId();
	}
};

#endif


#if defined(FILIN2)

struct Flare : public State {
	Flare(int id) : State(id) {}
	
	virtual void onEnter() {
		PropAccessor p;
		p().fcs.roll.set(Roll_TrackApp, 15);
		p().fcs.pitch.set(Pitch_VSpeed, -1.0f);
		p().fcs.yaw.set(Yaw_Damper);		
		p().fcs.throttle.set(Throttle_Value, -1);
		p().fcs.flaps.set(Flaps_Value, Flaps_Value_Landing);
		p().fcs.brakes.set(Brakes_Value, 0);

		p().fcs.watcher = Watcher_Idle;

		p().fcs.state = getId();
	}
};

#else

struct Flare : public State {
	Flare(int id) : State(id) {}

	virtual void onEnter() {
		ParamManager *parammgr = Manager::Instance().getParamManager();		
		
		PropAccessor p;

		p().fcs.roll.set(Roll_SetPoint, 0);
		p().fcs.pitch.set(Pitch_SetPoint, parammgr->getFloat(ParamManager::PITCH_FLARE));
		p().fcs.yaw.set(Yaw_Damper);
		p().fcs.throttle.set(Throttle_Value, 0, 0.3f);
		p().fcs.flaps.set(Flaps_Value, Flaps_Value_Landing);
		p().fcs.brakes.set(Brakes_Value, 0);

		p().fcs.watcher = Watcher_Idle;

		p().fcs.state = getId();
	}
};

#endif


struct Landing : public State {
	Landing() : State() {
		State *baroGlide = new BaroGlide(stateid::BAROGLIDE);
#if defined(FILIN2)
		State *vyGlide = new VyGlide(stateid::DIRECTGLIDE);
#else
		State *directGlide = new DirectGlide(stateid::DIRECTGLIDE);
#endif
		State *flare = new Flare(stateid::FLARE);

		setInitial(baroGlide);

#if defined(FILIN2)
		baroGlide->addTransition(evt_minimum_baro, vyGlide);
#else
		baroGlide->addTransition(evt_directalt, directGlide);
#endif
		baroGlide->addTransition(evt_glidepath_end, NULL);
		baroGlide->addTransition(evt_critical_failure, NULL);

#if defined(FILIN2)
		vyGlide->addTransition(evt_cmd_auto, flare);
		vyGlide->addTransition(evt_critical_failure, NULL);
		vyGlide->addTransition(evt_touchdown, NULL);
#else
		directGlide->addTransition(evt_flare_alt, flare);
		directGlide->addTransition(evt_directalt_lost, baroGlide);
		directGlide->addTransition(evt_touchdown, NULL);
#endif

		flare->addTransition(evt_touchdown, NULL);
		directGlide->addTransition(evt_stopped, NULL);
	}

	virtual void onEnter() {
		PropAccessor p;
		p().fcs.parachute_armed = false;
	}
};


// emergency descent without engine
struct LandingCutPower : public State {
	LandingCutPower(int id) : State(id) {}
	
	virtual void onEnter() {
		PropAccessor p;
		p().fcs.roll.set(Roll_Track, 30);
		p().fcs.pitch.set(Pitch_VSpeed, -3.0f);
		p().fcs.yaw.set(Yaw_Damper);		
		p().fcs.throttle.set(Throttle_Value, -1);
		p().fcs.flaps.set(Flaps_Value, Flaps_Value_Takeoff);
		p().fcs.brakes.set(Brakes_Value, 0);
		p().fcs.state = getId();
	}
};

// emergency descent without coordinates
struct LandingNoCoord : public State {
	LandingNoCoord(int id) : State(id) {}
	
	virtual void onEnter() {
		PropAccessor p;
		p().fcs.roll.set(Roll_SetPoint, 0);
		p().fcs.pitch.set(Pitch_VSpeed, -1.0f);
		p().fcs.yaw.set(Yaw_Damper);
		p().fcs.throttle.set(Throttle_Airspeed, Manager::Instance().getParamManager()->getFloat(ParamManager::VAPPROACH) / 3.6f);
		p().fcs.flaps.set(Flaps_Value, Flaps_Value_Landing);
		p().fcs.brakes.set(Brakes_Value, 0);
		p().fcs.state = getId();
	}
};

}

#endif
